/*   Copyright (C) 2011 Wolfgang Hankeln, Norma J. Wendel
 *
 *   This file is part of CDinFusion.
 *
 *   CDinFusion is free software: you can redistribute it and/or
 *   modify it under the terms of the GNU Lesser General Public 
 *   License in version 3 (LGPL3) as published by the Free Software
 *   Foundation version 3 of the License.
 *
 *   CDinFusion is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *   Lesser General Public License for more details.
 *
 *   You should have received a copy of the Lesser General Public
 *   License along with CDinFusion; see the file COPYING. If not,
 *   write to the Free Software Foundation, 59 Temple Place - Suite 330,
 *   Boston, MA 02111-1307, USA or see <http://www.gnu.org/licenses/>.
 *   
 *   If you have any questions, send an email to: megx@mpi-bremen.de.
 */
package org.cdinfusion.data;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.cdinfusion.data.environment.Air;
import org.cdinfusion.data.environment.Biofilm;
import org.cdinfusion.data.environment.Environment;
import org.cdinfusion.data.environment.Host_associated;
import org.cdinfusion.data.environment.Human_gut;
import org.cdinfusion.data.environment.Human_oral;
import org.cdinfusion.data.environment.Human_skin;
import org.cdinfusion.data.environment.Human_vaginal;
import org.cdinfusion.data.environment.Miscellaneous;
import org.cdinfusion.data.environment.None_Env;
import org.cdinfusion.data.environment.Plant_associated;
import org.cdinfusion.data.environment.Sediment;
import org.cdinfusion.data.environment.Soil;
import org.cdinfusion.data.environment.Wastewater;
import org.cdinfusion.data.environment.Water;
import org.cdinfusion.data.environment.generator.EnvironmentalSampleOnlyFastaHeaderGeneratorForEnvironment;
import org.cdinfusion.data.environment.generator.FastaHeaderGeneratorForEnvironment;
import org.cdinfusion.data.environment.generator.Host_associatedFastaHeaderGeneratorForEnvironment;
import org.cdinfusion.data.environment.generator.Human_gutFastaHeaderGeneratorForEnvironment;
import org.cdinfusion.data.environment.generator.Human_oralFastaHeaderGeneratorForEnvironment;
import org.cdinfusion.data.environment.generator.Human_skinFastaHeaderGeneratorForEnvironment;
import org.cdinfusion.data.environment.generator.Human_vaginalFastaHeaderGeneratorForEnvironment;
import org.cdinfusion.data.environment.generator.None_EnvFastaHeaderGeneratorForEnvironment;
import org.cdinfusion.data.environment.generator.Plant_associatedFastaHeaderGeneratorForEnvironment;
import org.cdinfusion.data.studytype.BA;
import org.cdinfusion.data.studytype.EU;
import org.cdinfusion.data.studytype.ME;
import org.cdinfusion.data.studytype.MIMARKS_C;
import org.cdinfusion.data.studytype.MIMARKS_S;
import org.cdinfusion.data.studytype.None_Study;
import org.cdinfusion.data.studytype.ORG;
import org.cdinfusion.data.studytype.PL;
import org.cdinfusion.data.studytype.StudyType;
import org.cdinfusion.data.studytype.VI;
import org.cdinfusion.data.studytype.generators.BAFastaHeaderGeneratorForStudyType;
import org.cdinfusion.data.studytype.generators.EUFastaHeaderGeneratorForStudyType;
import org.cdinfusion.data.studytype.generators.FastaHeaderGeneratorForStudyType;
import org.cdinfusion.data.studytype.generators.MEFastaHeaderGeneratorForStudyType;
import org.cdinfusion.data.studytype.generators.MIMARKS_CFastaHeaderGeneratorForStudyType;
import org.cdinfusion.data.studytype.generators.MIMARKS_SFastaHeaderGeneratorForStudyType;
import org.cdinfusion.data.studytype.generators.None_StudyFastaHeaderGeneratorForStudyType;
import org.cdinfusion.data.studytype.generators.ORGFastaHeaderGeneratorForStudyType;
import org.cdinfusion.data.studytype.generators.PLFastaHeaderGeneratorForStudyType;
import org.cdinfusion.data.studytype.generators.VIFastaHeaderGeneratorForStudyType;

public final class CDElementHelper {

    private static final Map<Class<?>, FastaHeaderGeneratorForEnvironment> ENVIRONMENT_GENERATOR_MAPPING;

    static {
	final Map<Class<?>, FastaHeaderGeneratorForEnvironment> tempEnvMap = new HashMap<Class<?>, FastaHeaderGeneratorForEnvironment>();

	tempEnvMap.put(Air.class, new EnvironmentalSampleOnlyFastaHeaderGeneratorForEnvironment());
	tempEnvMap.put(Biofilm.class, new EnvironmentalSampleOnlyFastaHeaderGeneratorForEnvironment());
	tempEnvMap.put(Host_associated.class, new Host_associatedFastaHeaderGeneratorForEnvironment());
	tempEnvMap.put(Human_gut.class, new Human_gutFastaHeaderGeneratorForEnvironment());
	tempEnvMap.put(Human_oral.class, new Human_oralFastaHeaderGeneratorForEnvironment());
	tempEnvMap.put(Human_skin.class, new Human_skinFastaHeaderGeneratorForEnvironment());
	tempEnvMap.put(Human_vaginal.class, new Human_vaginalFastaHeaderGeneratorForEnvironment());
	tempEnvMap.put(Miscellaneous.class, new EnvironmentalSampleOnlyFastaHeaderGeneratorForEnvironment());
	tempEnvMap.put(None_Env.class, new None_EnvFastaHeaderGeneratorForEnvironment());
	tempEnvMap.put(Plant_associated.class, new Plant_associatedFastaHeaderGeneratorForEnvironment());
	tempEnvMap.put(Sediment.class, new EnvironmentalSampleOnlyFastaHeaderGeneratorForEnvironment());
	tempEnvMap.put(Soil.class, new EnvironmentalSampleOnlyFastaHeaderGeneratorForEnvironment());
	tempEnvMap.put(Wastewater.class, new EnvironmentalSampleOnlyFastaHeaderGeneratorForEnvironment());
	tempEnvMap.put(Water.class, new EnvironmentalSampleOnlyFastaHeaderGeneratorForEnvironment());

	ENVIRONMENT_GENERATOR_MAPPING = Collections.unmodifiableMap(tempEnvMap);
    }

    private static final Map<Class<? extends StudyType>, FastaHeaderGeneratorForStudyType> STUDY_GENERATOR_MAPPING;

    static {
	final Map<Class<? extends StudyType>, FastaHeaderGeneratorForStudyType> tempStudyMap = new HashMap<Class<? extends StudyType>, FastaHeaderGeneratorForStudyType>();

	tempStudyMap.put(BA.class, new BAFastaHeaderGeneratorForStudyType());
	tempStudyMap.put(EU.class, new EUFastaHeaderGeneratorForStudyType());
	tempStudyMap.put(ME.class, new MEFastaHeaderGeneratorForStudyType());
	tempStudyMap.put(MIMARKS_C.class, new MIMARKS_CFastaHeaderGeneratorForStudyType());
	tempStudyMap.put(MIMARKS_S.class, new MIMARKS_SFastaHeaderGeneratorForStudyType());
	tempStudyMap.put(None_Study.class, new None_StudyFastaHeaderGeneratorForStudyType());
	tempStudyMap.put(ORG.class, new ORGFastaHeaderGeneratorForStudyType());
	tempStudyMap.put(PL.class, new PLFastaHeaderGeneratorForStudyType());
	tempStudyMap.put(VI.class, new VIFastaHeaderGeneratorForStudyType());

	STUDY_GENERATOR_MAPPING = Collections.unmodifiableMap(tempStudyMap);
    }

    /**
     * This is a helper class which cannot be instantiated.
     */
    private CDElementHelper() {
	// cannot be instantiated
    }

    /**
     * Returns all sequence IDs from {@code allSequenceIDs} that are included in
     * the given {@link CDElement}.
     * 
     * @param allSequenceIDs
     *            a list containing all sequence IDs.
     * @param cdElement
     *            the cd element whose sequence IDs should be retrieved.
     * @return all sequence IDs from {@code allSequenceIDs} that are included in
     *         the given {@link CDElement}.
     */
    public static List<String> getUsedSequenceIDs(final List<String> allSequenceIDs, final CDElement cdElement) {
	final List<String> result = new ArrayList<String>(cdElement.getNumberOfSequences());

	boolean started = false;
	for (String sequenceID : allSequenceIDs) {

	    if (sequenceID.equals(cdElement.getFirstSequenceID())) {
		started = true;
	    }
	    if (started) {
		result.add(sequenceID);
	    }
	    if (sequenceID.equals(cdElement.getLastSequenceID())) {
		started = false;
	    }
	}

	return result;
    }

    public static String generateHeader(final CDElement cdElement) {
	final StringBuilder header = new StringBuilder();
	header.append(cdElement.getCDFastaheader().toString());
	header.append(" ");
	CDElementHelper.generateOptionalFields(cdElement, header);

	return header.toString();
    }

    private static StringBuilder generateOptionalFields(final CDElement cdelement,
	    final StringBuilder optional) {

	final StudyType study = cdelement.getStudy();
	optional.append(STUDY_GENERATOR_MAPPING.get(study.getClass()).generateFastaHeader(study));

	final Environment environment = cdelement.getEnv();
	optional.append(ENVIRONMENT_GENERATOR_MAPPING.get(environment.getClass()).generateFastaHeader(
		environment));

	return optional;
    }
}